package me.jiatao.wan.data.network

import com.google.gson.JsonParseException
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.delay
import me.jiatao.wan.common.ext.isConnectedNetwork
import me.jiatao.wan.init.AppHelper
import org.json.JSONException
import retrofit2.HttpException
import timber.log.Timber
import java.io.IOException
import java.net.SocketTimeoutException
import java.net.UnknownHostException

/**
 * @Author: taojia
 * @CreateDate: 2021/8/24 5:33 下午
 * @Version: 1.0
 * @Description:
 */

/**
 * 请求异常处理
 * 将网络请求异常封装为HttpResult对象
 */
suspend inline fun <T> apiCall(crossinline call: suspend () -> HttpResult<T>): HttpResult<T> {
    val res: HttpResult<T>

    //拦截网络请求错误
    try {
        res = call()
    } catch (e: Throwable) {
        Timber.e(e, "request error--->${e.localizedMessage}")
        // 请求出错，将状态码和消息封装为 ResponseResult
        throw ApiException.build(e)
    }

    //拦截错误码
    return when (res.code) {
        HttpConst.CODE_SUCCESS -> {
            res
        }
        HttpConst.CODE_TOKEN_INVALID -> {
            //凭证失效，协程取消
            //执行退出登录操作等
            throw CancellationException()
        }
        else -> {
            throw ApiException(res.code, res.message)
        }
    }
}

/**
 * 返回请求数据
 */
suspend inline fun <T> apiDataCall(crossinline call: suspend () -> HttpResult<T>): T {
    //TODO:这里查看网络访问延迟效果，正式上线需要移除掉
    delay(1500)
    val httpResult = apiCall {
        call()
    }
    if (httpResult.data == null) {
        throw ApiException(HttpConst.CODE_DATA_NULL, "data is null")
    }

    return httpResult.data!!
}

/**
 * 返回请求状态
 */
suspend inline fun <T> apiStatusCall(crossinline call: suspend () -> HttpResult<T>): Boolean {
    val httpResult = apiCall {
        call()
    }
    if (httpResult.code == HttpConst.CODE_SUCCESS) {
        return true
    }

    return false
}

/**
 * 网络、数据解析错误处理
 */
class ApiException(
    private val code: Int,
    override val message: String?,
    override val cause: Throwable? = null
) : RuntimeException(message, cause) {
    companion object {
        // 网络状态码
        fun build(e: Throwable): ApiException {
            return if (!AppHelper.mContext.isConnectedNetwork()) {
                ApiException(HttpConst.CODE_NET_ERROR, "网络连接失败,请检测网络设置")
            } else if (e is HttpException) {
                ApiException(HttpConst.CODE_NET_ERROR, "网络异常(${e.code()},${e.message()})")

            } else if (e is UnknownHostException) {
                ApiException(HttpConst.CODE_NET_ERROR, "未识别域名,请检查后再试")

            } else if (e is SocketTimeoutException) {
                ApiException(HttpConst.CODE_TIMEOUT, "请求超时,请稍后再试")

            } else if (e is IOException) {
                ApiException(HttpConst.CODE_NET_ERROR, "网络异常(${e.message})")

            } else if (e is JsonParseException || e is JSONException) {
                // Json解析失败
                ApiException(HttpConst.CODE_JSON_PARSE_ERROR, "数据解析错误,请稍后再试")

            } else {
                ApiException(HttpConst.CODE_SERVER_ERROR, "系统错误(${e.message})")
            }
        }
    }

    fun <T> toResponse(): HttpResult<T> {
        return HttpResult(code, message)
    }
}